package com.power.project.controller;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.digest.SM3;
import com.power.common.cache.CacheKey;
import com.power.common.cache.CacheManager;
import com.power.common.domain.ResponseDTO;

import com.power.project.api.IAccountFeign;
import com.power.project.dao.Ww_userDao;
import com.power.project.enums.AccountConstant;
import com.power.project.enums.MangeTypeEnum;
import com.power.project.model.ha_manage;
import com.power.project.model.Ww_user;
import com.power.project.model.bo.PasswordBO;

import com.power.project.model.vo.AccountVo;
import com.power.project.model.vo.PasswordVO;
import com.power.project.service.Ha_manageService;
import com.power.project.service.Ww_userService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@RestController
@Api(value = "用户账户", tags = {"用户账户"})
public class AccountController implements IAccountFeign {
    /**
     * 密码错误次数限制，超过次数将账号锁定
     */
    @Value("${login.errortimes}")
    private Integer times;

    /**
     * 缓存过期时间
     */
    @Value("${login.keeptime}")
    private Integer keeptime;

    /**
     * 登录错误超出限制，将被锁定的时间
     */
    @Value("${login.locktime}")
    private Long period;
    @Resource
    private CacheManager cacheManager;
    @Value("${power.user.salt:power8650sunny}")
    private String user_salt;

    private SM3 sm3Service;

    @Resource
    private Ww_userService ww_userService;

    @Resource
    private Ww_userDao dao;

    @Resource
    private Ha_manageService ha_mangeService;


    // 配置SSO相关参数
    public ResponseDTO<AccountVo> login(String userid, String password) {
        AccountVo accountVo = new AccountVo();

        // 校验当前人是否是管理员
        MangeTypeEnum manageTypeEnum ;
        ha_manage ha_mange = this.ha_mangeService.getByUserid(userid);
        if(ObjUtil.isNotEmpty(ha_mange)){
            if(ha_mange.getOwner() == MangeTypeEnum.SUPER_MANGE.getCode()){
                // 超级管理员
                manageTypeEnum = MangeTypeEnum.SUPER_MANGE;
            }else {
                // 普通管理员
                manageTypeEnum = MangeTypeEnum.REGULAR_MANGE;
            }
        }else {
            return ResponseDTO.errorNoData("此账号没有权限！请联系系统管理员");
        }

        //  查询登录人信息
        PasswordVO passwordVO = this.ww_userService.queryUserPassword(userid);
        if (passwordVO == null) {
            return ResponseDTO.errorNoData("账号或密码错误！");
        }

        // 加密
        String pwd_Sm3 = encodeSM3(password);
        if (!pwd_Sm3.equals(passwordVO.getPassword())) {
            Object loginCache = Optional.ofNullable(cacheManager.get(CacheKey.ROOT + ":" + CacheKey.LOGIN_ERROR_TIMES + ":" + userid)).orElse(null);
            Integer loginErrorTimes = loginErrorTimesCache(loginCache, userid);
            String errorMsg;
            if (loginErrorTimes >= times) {
                // 记录该账号登录错误超出限制时间，加入缓存
                cacheManager.put_temp(CacheKey.ROOT + ":" + CacheKey.LOGIN_LOCKED_TIME + ":" + userid, localDatetime2s(LocalDateTime.now()), Math.toIntExact(period));
                errorMsg = "账号或密码错误, 不正确超过" + times + "次，账号已被锁定，" + period / 60 + "分钟后解锁";
            } else {
                errorMsg = "账号或密码错误, 当前登录失败:" + loginErrorTimes + "次, 超过" + times + "次将被锁定" + period / 60 + "分钟。";
            }
            return ResponseDTO.errorNoData(errorMsg);
        }
        cacheManager.remove(CacheKey.ROOT + ":" + CacheKey.LOGIN_ERROR_TIMES + ":" + userid);
        String loginId = passwordVO.getUserid();

        // 缓存登录信息
        accountVo.setUserInfo(sessionLogin(loginId));
        accountVo.getUserInfo().setOwner(manageTypeEnum.getCode());
        // 缓存token
        accountVo.setToken((String) SaResult.ok("登录成功！").setData(StpUtil.getTokenValue()).getData());

        return ResponseDTO.succData(accountVo);
    }

    @Override
    public ResponseDTO logout() {
        StpUtil.logout();
        return ResponseDTO.succMsg("登出成功");
    }

    @Override
    public ResponseDTO isLogin() {
        return ResponseDTO.succData(StpUtil.isLogin());
    }

    @Override
    public ResponseDTO notifyPassword(PasswordBO passwordBO) {

        PasswordVO passwordVO = ww_userService.queryUserPassword(passwordBO.getUserid());
        if (passwordVO == null) {
            return ResponseDTO.errorNoData("账号不存在！");
        }
        if (!passwordVO.getPassword().equals(encodeSM3(passwordBO.getPassword()))) {
            return ResponseDTO.errorNoData("原密码错误！");
        }
        try {
            dao.updataByUserId(passwordBO.getUserid(), encodeSM3(passwordBO.getNewPassword()));
        }catch (Exception e){
            return ResponseDTO.errorNoData("修改失败！");
        }

        return ResponseDTO.succ();
//        System.out.println(isValidPassword(passwordVO.getPassword()));
//        if (isValidPassword(passwordVO.getPassword())) {
//
//        }else{
//            return ResponseDTO.errorNoData("输入的密码格式不符合！");
//        }
    }
    public static boolean isValidPassword(String password) {
        // 正则表达式定义密码格式要求：包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符，且长度在8到20之间
        String regex = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=!_]).{8,20}$";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(password);

        return matcher.matches();
    }

    private  String encodeSM3(String original) {
        if (sm3Service == null) {
            sm3Service = SmUtil.sm3();
            sm3Service.setSalt(user_salt.getBytes()); // 加盐
        }

        return sm3Service.digestHex(original).toLowerCase();
    }

//    public static void main(String[] args) {
//                System.out.println( SmUtil.sm3().setSalt("power8650sunny".getBytes()).digestHex("ncsf_12348").toLowerCase());
//    }

    /**
     * 根据用户id，加载权限，存入会话
     *
     * @param loginId
     */
    private Ww_user sessionLogin(Object loginId) {
        // 缓存登录id
        StpUtil.login(loginId);

        // 构建用户对象
        Ww_user ww_user = this.ww_userService.getByUserId(loginId.toString());

        // 登录信息存入缓存
        SaSession saSession = StpUtil.getTokenSession();
        saSession.set(AccountConstant.USER, ww_user);
        saSession.update();

        return ww_user;
    }

    /**
     * 计算登录失败次数
     */
    private Integer loginErrorTimesCache(Object cacheValue, String userName) {
        Integer loginErrorTimes = 1;
        if (cacheValue == null) {
            // 登录错误次数缓存
            cacheManager.put_temp(CacheKey.ROOT + ":" + CacheKey.LOGIN_ERROR_TIMES + ":" + userName, String.valueOf(loginErrorTimes), keeptime);
        } else {
            // 未超过限定次数则错误次数+1
            String errorTimes = cacheManager.get(CacheKey.ROOT + ":" + CacheKey.LOGIN_ERROR_TIMES + ":" + userName).toString();
            loginErrorTimes = Integer.valueOf(errorTimes);
            cacheManager.put_temp(CacheKey.ROOT + ":" + CacheKey.LOGIN_ERROR_TIMES + ":" + userName, String.valueOf(++loginErrorTimes), keeptime);
        }
        return loginErrorTimes;
    }

    public static String localDatetime2s(LocalDateTime time) {
        if (time == null) {
            return null;
        }
        // 创建对应的pattern，注意T和Z两个字符使用单引号引起来，毫秒值使用大写S表示
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return dtf.format(time);
    }
}
